001 /*
002 * Copyright 2005 Stephen J. McConnell
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
013 * implied.
014 *
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package net.dpml.tools.info;
020
021 import java.io.File;
022 import java.io.IOException;
023 import java.io.FileNotFoundException;
024 import java.io.FileInputStream;
025 import java.io.BufferedInputStream;
026 import java.net.URI;
027 import java.net.URL;
028 import java.util.Properties;
029 import java.util.Arrays;
030
031 import net.dpml.transit.Artifact;
032 import net.dpml.transit.Transit;
033
034 import net.dpml.util.ElementHelper;
035
036 import org.w3c.dom.Element;
037
038 /**
039 * Utility class used for construction of a module model from an XML source.
040 *
041 * @author <a href="http://www.dpml.net">The Digital Product Meta Library</a>
042 * @version 1.0.0
043 */
044 public final class BuilderDirectiveHelper
045 {
046 private static final String BUILDER_ELEMENT_NAME = "builder";
047 private static final String LISTENERS_ELEMENT_NAME = "listeners";
048 private static final String LISTENER_ELEMENT_NAME = "listener";
049 private static final String PROPERTIES_ELEMENT_NAME = "properties";
050 private static final String PROPERTY_ELEMENT_NAME = "property";
051
052 private BuilderDirectiveHelper()
053 {
054 // static utility class
055 }
056
057 /**
058 * Construct a builder directive from XML source.
059 * @param source the XML source file
060 * @return the builder directive
061 * @exception IOException if an IO exception occurs
062 */
063 public static BuilderDirective build( File source ) throws IOException
064 {
065 if( null == source )
066 {
067 throw new NullPointerException( "source" );
068 }
069 if( !source.exists() )
070 {
071 throw new FileNotFoundException( source.toString() );
072 }
073 if( source.isDirectory() )
074 {
075 final String error =
076 "File ["
077 + source
078 + "] references a directory.";
079 throw new IllegalArgumentException( error );
080 }
081 FileInputStream input = new FileInputStream( source );
082 BufferedInputStream buffer = new BufferedInputStream( input );
083 try
084 {
085 final Element root = ElementHelper.getRootElement( input );
086 File base = source.getParentFile();
087 return buildMainDirective( root );
088 }
089 catch( Throwable e )
090 {
091 final String error =
092 "An error occured while attempting to create the builder configuration from the source: "
093 + source;
094 IOException ioe = new IOException( error );
095 ioe.initCause( e );
096 throw ioe;
097 }
098 finally
099 {
100 input.close();
101 }
102 }
103
104 /**
105 * Creates a builder configuration using the default configuration.
106 * @return the builder directive
107 * @exception Exception if an error occurs
108 */
109 public static BuilderDirective build() throws Exception
110 {
111 File prefs = Transit.DPML_PREFS;
112 File config = new File( prefs, "dpml/tools/xmls/builder.xml" );
113 if( config.exists() )
114 {
115 return build( config );
116 }
117 else
118 {
119 final String error =
120 "Missing builder configuration: "
121 + config;
122 throw new FileNotFoundException( error );
123 }
124 }
125
126 private static URL convertToURL( URI uri ) throws Exception
127 {
128 if( Artifact.isRecognized( uri ) )
129 {
130 Artifact artifact = Artifact.createArtifact( uri );
131 return artifact.toURL();
132 }
133 else
134 {
135 return uri.toURL();
136 }
137 }
138
139 /**
140 * Build the configuration using an XML element.
141 * @param element the builder root element
142 * @return the builder directive
143 * @exception IOException if an I/O error occurs
144 */
145 private static BuilderDirective buildMainDirective( Element element ) throws Exception
146 {
147 final String elementName = element.getTagName();
148 if( !BUILDER_ELEMENT_NAME.equals( elementName ) )
149 {
150 final String error =
151 "Element is not a builder configuration.";
152 throw new IllegalArgumentException( error );
153 }
154
155 // get type descriptors, modules and properties
156
157 String phase = ElementHelper.getAttribute( element, "default", "installation" );
158
159 Properties properties = null;
160 ListenerDirective[] listeners = new ListenerDirective[0];
161 Element[] children = ElementHelper.getChildren( element );
162 for( int i=0; i<children.length; i++ )
163 {
164 Element child = children[i];
165 final String tag = child.getTagName();
166 if( PROPERTIES_ELEMENT_NAME.equals( tag ) )
167 {
168 properties = buildProperties( child );
169 }
170 else if( LISTENERS_ELEMENT_NAME.equals( tag ) )
171 {
172 listeners = buildListenerDirectives( child );
173 }
174 else
175 {
176 final String error =
177 "Illegal element name [" + tag + "] within 'builder' element.";
178 throw new IllegalArgumentException( error );
179 }
180 }
181 Arrays.sort( listeners );
182 return new BuilderDirective( listeners, phase, properties );
183 }
184
185 private static ListenerDirective[] buildListenerDirectives( Element element ) throws Exception
186 {
187 Element[] children = ElementHelper.getChildren( element );
188 ListenerDirective[] types = new ListenerDirective[ children.length ];
189 for( int i=0; i<children.length; i++ )
190 {
191 Element child = children[i];
192 types[i] = buildListenerDirective( child );
193 }
194 return types;
195 }
196
197 private static ListenerDirective buildListenerDirective( Element element ) throws Exception
198 {
199 final String tag = element.getTagName();
200 if( LISTENER_ELEMENT_NAME.equals( tag ) )
201 {
202 final String name = ElementHelper.getAttribute( element, "name", null );
203 final String spec = ElementHelper.getAttribute( element, "uri", null );
204 final URI uri = createURI( spec );
205 final String classname = ElementHelper.getAttribute( element, "class", null );
206 final String value = ElementHelper.getAttribute( element, "priority", null );
207 int priority = Integer.parseInt( value );
208 final String deps = ElementHelper.getAttribute( element, "depends", null );
209 final Properties properties = buildProperties( element );
210 return new ListenerDirective( name, priority, uri, classname, properties );
211 }
212 else
213 {
214 final String error =
215 "Invalid resource element name ["
216 + tag
217 + "].";
218 throw new IllegalArgumentException( error );
219 }
220 }
221
222 private static Properties buildProperties( Element element )
223 {
224 Properties properties = new Properties();
225 Element[] children = ElementHelper.getChildren( element );
226 for( int i=0; i<children.length; i++ )
227 {
228 Element child = children[i];
229 String tag = child.getTagName();
230 if( PROPERTY_ELEMENT_NAME.equals( tag ) )
231 {
232 String key = ElementHelper.getAttribute( child, "name", null );
233 if( null == key )
234 {
235 final String error =
236 "Property declaration does not contain a 'name' attribute.";
237 throw new IllegalArgumentException( error );
238 }
239 else
240 {
241 String value = ElementHelper.getAttribute( child, "value", null );
242 properties.setProperty( key, value );
243 }
244 }
245 }
246 return properties;
247 }
248
249 private static URI createURI( String spec ) throws Exception
250 {
251 if( null == spec )
252 {
253 return null;
254 }
255 else
256 {
257 return new URI( spec );
258 }
259 }
260
261 }